//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <assert.h>
#include <car.h>
#include "marshal.h"
#include "prxstub.h"
#include "rot.h"
#include <stdlib.h>
#include <aura.h>
#include <sharecls.h>
#include <classinfo.h>
#include <pcentral.h>
#include <elapi.h>

EXTERN_C const InterfaceID EIID_IProxy;


PInterface CInterfaceProxy::S_Probe(
        /* [in] */ CInterfaceProxy *pThis,
        /* [in] */ REIID riid)
{
    return pThis->m_pOwner->Probe(riid);
}

UInt32 CInterfaceProxy::S_AddRef(CInterfaceProxy *pThis)
{
    return pThis->m_pOwner->AddRef();
}

UInt32 CInterfaceProxy::S_Release(CInterfaceProxy *pThis)
{
    return pThis->m_pOwner->Release();
}

ECode CInterfaceProxy::BufferSize(
    /* [in] */ UInt32 uMethodIndex,
    /* [in] */ UInt32 *puArgs,
    /* [out] */ UInt32 *puInSize,
    /* [out] */ UInt32 *puOutSize)
{
    ECode ec;
    const CIMethodEntry *pMethodInfo;
    pMethodInfo = &(m_pInfo->methods[uMethodIndex]);

    if (m_pContext == CTX_USER_2_KERN) {
        ec = Proxy_UserToKernMsh_BufferSize(
            pMethodInfo,
            puArgs,
            puInSize,
            puOutSize);
    }
    else {
        assert(CTX_KERN_2_USER == m_pContext
            || CTX_DIFF_PROCESS == m_pContext
            || CTX_DIFF_MACHINE == m_pContext);
        ec = Proxy_ProcessMsh_BufferSize(
                 pMethodInfo,
                 puArgs,
                 puInSize,
                 puOutSize);
        if (0 != *puOutSize){
            *puOutSize += sizeof(MarshalHeader);
        }
    }

    if (SUCCEEDED(ec)) {
        *puInSize += sizeof(MarshalHeader);
    }
    return ec;
}

ECode CInterfaceProxy::MarshalIn(
    /* [in] */ UInt32 uMethodIndex,
    /* [in] */ UInt32 *puArgs,
    /* [out] */ MarshalHeader *pHeader)
{
    ECode ec;
    const CIMethodEntry *pMethodInfo;
    pMethodInfo = &(m_pInfo->methods[uMethodIndex]);

    if (m_pContext == CTX_USER_2_KERN) {
        ec = Proxy_UserToKernMsh_In(
                 pMethodInfo,
                 puArgs,
                 (UInt32 *)(pHeader + 1) + 1);
        // (puArgs - 1), It's "this" address
        *(UInt32*)(pHeader + 1) = (UInt32)(puArgs - 1);
    }
    else {
        assert(m_pContext == CTX_KERN_2_USER
             || m_pContext == CTX_DIFF_PROCESS
             || m_pContext == CTX_DIFF_MACHINE);

        ec = Proxy_ProcessMsh_In(
                 pMethodInfo,
                 puArgs,
                 (UInt32 *)(pHeader + 1));
    }

    if (SUCCEEDED(ec)) {
        pHeader->m_uMagic = MARSHAL_MAGIC;
        pHeader->m_oid = m_oid;
        pHeader->m_hInterfaceIndex = m_uIndex;
        pHeader->m_hMethodIndex = uMethodIndex + 3;
        pHeader->m_pContext = m_pContext;
    }

    return ec;
}

ECode CInterfaceProxy::UnmarshalOut(
    /* [in] */ UInt32 uMethodIndex,
    /* [out] */ MarshalHeader *pHeader,
    /* [in] */ UInt32 *puArgs)
{
    ECode ec;

    if (m_pContext == CTX_USER_2_KERN) {
            ec = Proxy_UserToKernUnmsh_Out(
                     &(m_pInfo->methods[uMethodIndex]),
                     (UInt32 *)pHeader,
                     puArgs);
    }
    else {

        if (pHeader->m_uMagic != MARSHAL_MAGIC) {
            MARSHAL_DBGOUT(MSHDBG_ERROR,
                printf("Proxy unmsh: invalid magic(%x)\n", pHeader->m_uMagic));
            return E_MARSHAL_DATA_TRANSPORT_ERROR;
        }

#if defined(_DEBUG)
        if (pHeader->m_oid != m_oid) {
            MARSHAL_DBGOUT(MSHDBG_ERROR,
                printf("Proxy unmsh: invalid oid(%x)\n", pHeader->m_oid));
            return E_MARSHAL_DATA_TRANSPORT_ERROR;
        }
        if (pHeader->m_hInterfaceIndex != (Int16)m_uIndex) {
            MARSHAL_DBGOUT(MSHDBG_ERROR,
                printf("Proxy unmsh: invalid iidx(%x)\n",
                pHeader->m_hInterfaceIndex));
            return E_MARSHAL_DATA_TRANSPORT_ERROR;
        }
        if (pHeader->m_pContext != m_pContext) {
            MARSHAL_DBGOUT(MSHDBG_ERROR,
            printf("Proxy unmsh: invalid ctx(%x)\n", pHeader->m_pContext));
            return E_MARSHAL_DATA_TRANSPORT_ERROR;

        }
        if (pHeader->m_hMethodIndex != (Int16)(uMethodIndex + 3)) {
            MARSHAL_DBGOUT(MSHDBG_ERROR, printf(
                "Proxy unmsh: invalid method(%x)\n", pHeader->m_hMethodIndex));
        }
#endif

        assert(m_pContext == CTX_DIFF_PROCESS
            || m_pContext == CTX_DIFF_MACHINE
            || m_pContext == CTX_KERN_2_USER);

        ec = Proxy_ProcessUnmsh_Out(
                 &(m_pInfo->methods[uMethodIndex]),
                 (UInt32 *)(pHeader + 1),
                 pHeader->m_uOutSize - sizeof(MarshalHeader),
                 puArgs);
    }

    return ec;
}

UInt32 CInterfaceProxy::CountMethodArgs(
    /* [in] */ UInt32 uMethodIndex)
{
    return GET_LENGTH((m_pInfo->methods[uMethodIndex]).reserved1);
}

#ifdef _arm

EXTERN_C void __ProxyEntry(void);

EXTERN_C ECode GlobalProxyEntry(UInt32 *puArgs)
{
    return CInterfaceProxy::ProxyEntry(puArgs);
}

#ifdef _GNUC
#define DECL_PROXY_ENTRY()              \
    __asm__(                            \
        ".text;"                        \
        ".align 4;"                     \
        ".globl ___ProxyEntry;"         \
        "___ProxyEntry:"                \
        "stmdb  sp!, {r1, lr};"         \
        "add    r0, sp, #4;"            \
        "bl     _GlobalProxyEntry;"     \
        "ldr    lr, [sp, #4];"          \
        "add    sp, sp, #24;"           \
        "mov    pc, lr;"                \
    )

DECL_PROXY_ENTRY();
#endif

#endif

#ifdef _mips

EXTERN_C ECode GlobalProxyEntry(UInt32 *puArgs)
{
    return CInterfaceProxy::ProxyEntry(puArgs);
}

#ifdef _GNUC
void __ProxyContinue()
{
DECL_ASMENTRY(ProxyContinue)
#elif defined(_EVC)
DECL_NAKED void ProxyContinue()
{
#else
#error unknown compiler
#endif
    ASM(
        "sw     $4, 0x0($29);"
        "sw     $5, 0x4($29);"
        "sw     $6, 0x8($29);"
        "sw     $7, 0xc($29);"
        "addiu  $29, $29, -0x1c;"
        "sw     $12, 0x10($29);"
        "add    $4, $29, 0x18;"
        "sw     $4, 0x14($29);"
        "la     $9, GlobalProxyEntry;"
        "jalr   $9;"
        "addiu  $29, $29, 0x1c;"
        "lw     $31, -4($29);"
        "jr     $31;");
}
#endif

ECode CInterfaceProxy::ProxyEntry(UInt32 *puArgs)
{
    CInterfaceProxy *pThis;
    UInt32 uMethodIndex, uInSize, uOutSize;
    MarshalHeader *pInHeader = NULL, *pOutHeader = NULL;
    PVoid pInBuff = NULL, pOutBuff = NULL;
    ECode ec, orgec;

#if !defined(_mips)
    UInt32 cArgs;
#endif


    puArgs++; // skip ret address

    pThis = (CInterfaceProxy *)*puArgs;
    puArgs++; // skip this

    MARSHAL_DBGOUT(MSHDBG_NORMAL,
        printf("*puArgs = %x, puArgs = %x", *puArgs, puArgs));
    MARSHAL_DBGOUT(MSHDBG_NORMAL,
        printf("Enter proxy: oid(%x)\n", pThis->m_oid));
    MARSHAL_DBGOUT(MSHDBG_NORMAL, printf("iid: "));
    MARSHAL_DBGOUT(MSHDBG_NORMAL, DUMP_GUID(pThis->m_pInfo->iid));

#if defined(_x86) || defined(_win32)
    uMethodIndex = CalcMethodIndex(*(UInt32 *)((UInt32)&puArgs - 4));
#elif defined(_arm)
    uMethodIndex = puArgs[-3];
#elif defined(_mips)
    uMethodIndex = CalcMethodIndex(*(puArgs - 4) - 4);
#else
#error unknown architecture
#endif

#if !defined(_mips)
    // Get the stack length, not contain "this"
    cArgs = pThis->CountMethodArgs(uMethodIndex);

    MARSHAL_DBGOUT(MSHDBG_NORMAL, printf(
        "Method index(%d), args size(%d)\n", uMethodIndex + 3, cArgs * 4));
#endif

    // Calculate the package size
    //
    // NOTE:
    //  1. Alloc pOutHeader on the stack with MAX-out-size
    //  2. Assign pInHeader->m_uOutSize with MAX-out-size
    //  3. Pass the MIN-out-size to SysInvoke's last parameter
    //  4. Call Thread::ReallocBuffer in SysReply if necessary to pass back the
    //      marshaled-out data with error info
    //
    ec = pThis->BufferSize(uMethodIndex, puArgs, &uInSize, &uOutSize);
    if (FAILED(ec)) {
        MARSHAL_DBGOUT(MSHDBG_ERROR,
            printf("Proxy BufferSize() failed, ec = %x\n", ec));
        goto ProxyExit;
    }

    MARSHAL_DBGOUT(MSHDBG_NORMAL, printf(
        "Buffer size: isize(%d), osize(%d)\n", uInSize, uOutSize));
    assert(uInSize >= sizeof(MarshalHeader));

    pInBuff = (PVoid)_alloca(uInSize + sizeof(UInt32));
    if (!pInBuff) {
        ec = E_OUT_OF_MEMORY;
        goto ProxyExit;
    }

    SET_REQUEST_TYPE(pInBuff,Request_MethodCall);
    pInHeader = (MarshalHeader*)BY_REFERENCE(pInBuff, 1);

    pInHeader->m_uInSize = uInSize;
    pInHeader->m_uOutSize = uOutSize;

    if (pThis->m_pContext == CTX_DIFF_PROCESS ||
        pThis->m_pContext == CTX_DIFF_MACHINE) {

        if (pInHeader->m_uOutSize <
                sizeof(MarshalHeader) + ERROR_INFO_SIZE) {
            pInHeader->m_uOutSize = sizeof(MarshalHeader) + ERROR_INFO_SIZE;
            uOutSize = pInHeader->m_uOutSize;
        }
    }

    if (pInHeader->m_uOutSize) {
        pOutBuff = (PVoid)_alloca(REPLY_BUF_SIZE(uOutSize));
        if (NULL == pOutBuff) {
            ec = E_OUT_OF_MEMORY;
            goto ProxyExit;
        }
    }

    ec = pThis->MarshalIn(uMethodIndex, puArgs, pInHeader);
    if (SUCCEEDED(ec)) {
        MARSHAL_DBGOUT(MSHDBG_NORMAL, printf(
            "Before SysInvoke: oid(%d), isize(%d)\n", pThis->m_oid, uInSize));

        void * pLock = _Elastos_SequencedContext_Leave();
        CObjectProxy * pProxy = pThis->m_pOwner;
        ec = pProxy->m_channelPool.WriteAndRead(
                                      pInBuff,
                                      REQUEST_BUF_SIZE(uInSize),
                                      pOutBuff,
                                      REPLY_BUF_SIZE(uOutSize));
        _Elastos_SequencedContext_Enter(pLock);

        if (FAILED(ec)){
            //MARSHAL_DBGOUT(MSHDBG_ERROR,
            //            printf("AuraIpcChannel_SyncWrite failed.\n"));
            goto ProxyExit;
        }
        MARSHAL_DBGOUT(MSHDBG_NORMAL, Aura_printf(
            "After IpcInvoke: ec(%x), osize(%d)\n",
            ec, pInHeader->m_uOutSize));

        UInt32 replyType;
        GET_REPLY_TYPE(pOutBuff, replyType);
        assert((Reply_ECodeAndOutput == replyType)
               || (Reply_ECodeOnly == replyType));

        GET_REPLY_ECODE(pOutBuff, ec);
        pOutHeader = (MarshalHeader*)BY_REFERENCE(pOutBuff, 2);

        if (pOutHeader) {
            if (SUCCEEDED(ec)) {
                orgec = pThis->UnmarshalOut(uMethodIndex, pOutHeader, puArgs);
                if (FAILED(orgec)) {
                    ec = orgec;
                }
            }
            else if (IsUserECode(ec)) {

                ProxyUnmarshalOutErrorInfo(pOutHeader);
            }
        }
        else {
            MARSHAL_DBGOUT(MSHDBG_WARNING,
                printf("proxy SysInvoke() exit. oid = %d, ec = %x\n", \
                   pThis->m_oid, ec));
        }

    }
    else {
        MARSHAL_DBGOUT(MSHDBG_ERROR,
            printf("proxy MarshalIn() failed. ec = %x\n", ec));
    }

ProxyExit:
    MARSHAL_DBGOUT(MSHDBG_NORMAL, printf("Exit proxy: ec(%x)\n", ec));

#if !defined(_mips)
    SYS_PROXY_EXIT(ec, &puArgs - 1, cArgs);
#else
    SYS_PROXY_EXIT(ec, &puArgs - 1, 0);
#endif
}

static const EMuid ECLSID_XOR_CallbackSink = \
/* e724df56-e16a-4599-8edd-a97ab245d583 */
{0xe724df56,0xe16a,0x4599,{0x8e,0xdd,0xa9,0x7a,0xb2,0x45,0xd5,0x83}};

PInterface CObjectProxy::Probe(REIID riid)
{
    int n;

    if (riid == EIID_IInterface || riid == EIID_IProxy) {
        return (IInterface *)this;
    }
    else if (riid == EIID_CLASS_INFO) {
        return (IInterface *)&((CIClassEntry*)m_pInfo)->clsid;
    }

    if (riid == EIID_CALLBACK_CONNECTOR) {
        if (NULL == m_pICallbackConnector) {
            ClassID ezclsid;
            IInterface *pTemp = (IInterface *)&(m_pInterfaces[0].m_pvVptr);
            this->GetClsid(&ezclsid.clsid);

            ezclsid.clsid.Data1    ^= ECLSID_XOR_CallbackSink.Data1;
            ezclsid.clsid.Data2    ^= ECLSID_XOR_CallbackSink.Data2;
            ezclsid.clsid.Data3    ^= ECLSID_XOR_CallbackSink.Data3;
            ezclsid.clsid.Data4[0] ^= ECLSID_XOR_CallbackSink.Data4[0];
            ezclsid.clsid.Data4[1] ^= ECLSID_XOR_CallbackSink.Data4[1];
            ezclsid.clsid.Data4[2] ^= ECLSID_XOR_CallbackSink.Data4[2];
            ezclsid.clsid.Data4[3] ^= ECLSID_XOR_CallbackSink.Data4[3];
            ezclsid.clsid.Data4[4] ^= ECLSID_XOR_CallbackSink.Data4[4];
            ezclsid.clsid.Data4[5] ^= ECLSID_XOR_CallbackSink.Data4[5];
            ezclsid.clsid.Data4[6] ^= ECLSID_XOR_CallbackSink.Data4[6];
            ezclsid.clsid.Data4[7] ^= ECLSID_XOR_CallbackSink.Data4[7];
            ezclsid.pUunm = (wchar_t*)_alloca(sizeof(wchar_t) \
                        * (strlen(((CIClassEntry*)m_pInfo)->pszUunm) + 1));
            _strtowcs(ezclsid.pUunm, ((CIClassEntry*)m_pInfo)->pszUunm);
            _CObject_AcquireClassFactory(ezclsid, CTX_SAME_DOMAIN, &pTemp);
            m_pICallbackConnector = (ICallbackConnector*)pTemp;
        }
        return (IInterface*)m_pICallbackConnector;
    }

    for (n = 0; n < m_cInterfaces; n++) {
        if (riid == m_pInterfaces[n].m_pInfo->iid) {
            break;
        }
    }
    if (n == m_cInterfaces) {
        MARSHAL_DBGOUT(MSHDBG_WARNING, printf(
            "Proxy(%d): QI failed, iid: ", m_oid));
        MARSHAL_DBGOUT(MSHDBG_WARNING, DUMP_GUID(riid));

        return NULL;
    }

    return (IInterface *)&(m_pInterfaces[n].m_pvVptr);
}

UInt32 CObjectProxy::AddRef(void)
{
    Int32 lRefs = m_cRefs.Increment();

    MARSHAL_DBGOUT(MSHDBG_CREF, printf(
        "Proxy(%d) AddRef: %d\n", m_oid, lRefs));
    return (UInt32)lRefs;
}

extern PVoid g_marshalLock;

UInt32 CObjectProxy::Release(void)
{
    ECode ec;

    AuraCriticalSection_Enter(g_marshalLock);

    Int32 lRefs = m_cRefs.Decrement();

    if (lRefs == 0) {
        MARSHAL_DBGOUT(MSHDBG_NORMAL, printf(
            "Proxy(%d) destructed, context = %x\n", m_oid,
            m_pInterfaces[0].m_pContext));
        ec = UnregisterImportObject(m_oid);

        AuraCriticalSection_Leave(g_marshalLock);
        if (S_FALSE == ec) {
            return 1;// other thread hold the proxy
        }

        if (m_pICallbackConnector) {
            m_pICallbackConnector->DisconnectCallbackSink();
            delete m_pICallbackConnector;
        }

        // Release stub's reference before destroy self.
        //

        DetachServer(&m_channelPool, m_oid, m_pInterfaces[0].m_pContext);
        UnregisterSharedClassInfo((CIClassInfo*)m_pInfo);

        delete this;

        return 0;
    }
    else {
        AuraCriticalSection_Leave(g_marshalLock);
    }

    MARSHAL_DBGOUT(MSHDBG_CREF, printf(
        "Proxy(%d) Release: %d\n", m_oid, lRefs));

    return (UInt32)lRefs;
}

ECode CObjectProxy::Aggregate(
        /* [in] */ AggregateType type,
        /* [in] */ IInterface *pObj)
{
    return E_NOT_IMPLEMENTED;
}

ECode CObjectProxy::GetDomain(
        /* [out] */ IInterface **ppObj)
{
    return E_NOT_IMPLEMENTED;
}

ECode CObjectProxy::IndexQI(
        /* [in] */ UInt32 uIndex,
        /* [out] */ IInterface **ppObj)
{
    if (uIndex < (UInt32)m_cInterfaces) {
        *ppObj = (IInterface *)&(m_pInterfaces[uIndex].m_pvVptr);
        this->AddRef();
        return NOERROR;
    }
    MARSHAL_DBGOUT(MSHDBG_WARNING, printf(
        "Proxy(%d): IndexQI failed - idx(%d), cInterfaces(%d)\n",
        m_oid, uIndex, m_cInterfaces));

    return E_NO_INTERFACE;
}

ECode CObjectProxy::QI_Index(
             /* [in] */ IInterface **ppObj,
             /* [out] */ UInt32* pIndex)
{
    Int32 Index = 0;

    while (Index < m_cInterfaces) {
        if ((Void*)*ppObj == &(m_pInterfaces[Index].m_pvVptr)) {
            *pIndex = Index;
            return NOERROR;
        }
        Index++;
    }
    return E_NO_INTERFACE;
}

ECode CObjectProxy::GetOid(
        /* [out] */ oid_t *pOid)
{
    *pOid = m_oid;
    return NOERROR;
}

ECode CObjectProxy::GetClsid(
        /* [out] */ EMuid *pClsid)
{
    *pClsid = ((CIClassEntry*)m_pInfo)->clsid;
    return NOERROR;
}

ECode CObjectProxy::GetClassEntry(
        /* [out] */ UInt32 *pClassEntry)
{
    *pClassEntry = m_pInfo;
    return NOERROR;
}

ECode CObjectProxy::S_CreateObject(
        /* [in] */ oid_t oid,
        /* [in] */ REMuid rclsid,
        /* [in] */ UInt32 * pClassEntry,
        /* [in] */ PContext pContext,
        /* [out] */ IProxy **ppIProxy)
{
    CObjectProxy *pProxy;
    CInterfaceProxy *pInterfaces;
    UInt32 *pVtbl;
    int n, m, cMethods;
    ECode ec;
    UInt32 Entry;
    WStringBuf_<20> channelName;

    assert(oid != 0);
    assert(pContext == CTX_DIFF_PROCESS || pContext == CTX_DIFF_MACHINE
        || pContext == CTX_USER_2_KERN);
    assert(ppIProxy != NULL);

    pProxy = new CObjectProxy();
    if (!pProxy) {
        MARSHAL_DBGOUT(MSHDBG_ERROR,
            printf("Create proxy object: out of memory.\n"));
        return E_OUT_OF_MEMORY;
    }

//    pProxy->m_channelName = (wchar_t*)Aura_malloc(sizeof(wchar_t) * IPC_MAX_CHANNEL_NAME_LEN);
//    if(!(pProxy->m_channelName)) {
//        MARSHAL_DBGOUT(MSHDBG_ERROR,
//        	Aura_printf("malloc: out of memory.\n"));
//        return E_OUT_OF_MEMORY;
//    }

    ec = CPseudoCentral::SrvcGetChannelName(oid, &channelName);
    if (FAILED(ec)) {
        ec = E_FAIL;
        goto ErrorExit;
    }
    ec = pProxy->m_channelPool.Initialize(channelName);
    if (FAILED(ec)) {
        ec = E_FAIL;
        goto ErrorExit;
    }

    // if (System Object), Find it in local ClassInfo Table,
    // else m_pInfo = the input value(find in global Shared clsinfo
    // Table)
    ec = LookupServerClassEntry(rclsid, (const CIClassEntry**)&Entry);
    if (SUCCEEDED(ec)) {
        pProxy->m_pInfo = Entry;
    }
    else {
        ec = GetRemoteClassEntry(&pProxy->m_channelPool, rclsid,
                        (CIClassEntry **)&pProxy->m_pInfo);
        if (FAILED(ec)) {
            goto ErrorExit;
        }
    }

    pProxy->m_oid = oid;
    pProxy->m_cInterfaces = ((CIClassEntry*)(pProxy->m_pInfo))->interfaceNum;
    pInterfaces = new CInterfaceProxy[pProxy->m_cInterfaces];
    if (!pInterfaces) {
        MARSHAL_DBGOUT(MSHDBG_ERROR,
            printf("Create proxy interfaces: out of memory.\n"));
        ec = E_OUT_OF_MEMORY;
        goto ErrorExit;
    }
    pProxy->m_pInterfaces = pInterfaces;
    memset(pInterfaces, 0, sizeof(CInterfaceProxy) * pProxy->m_cInterfaces);
    for (n = 0; n < pProxy->m_cInterfaces; n++) {
        pInterfaces[n].m_oid = oid;
        pInterfaces[n].m_uIndex = n;
        pInterfaces[n].m_pContext = pContext;
        pInterfaces[n].m_pOwner = pProxy;
        CIInterfaceEntry *pInterfaceInfo =
            (CIInterfaceEntry *)GetUnalignedPtr(
                ((CIClassEntry *)(pProxy->m_pInfo))->interfaces + n);
        pInterfaces[n].m_pInfo = pInterfaceInfo;

        cMethods = pInterfaceInfo->methodNumMinus3 + 3;
        pVtbl = new UInt32[cMethods];
        if (!pVtbl) {
            MARSHAL_DBGOUT(MSHDBG_ERROR,
                printf("Create proxy vtbl: out of memory.\n"));
            return E_OUT_OF_MEMORY;
        }
        pInterfaces[n].m_pvVptr = pVtbl;

#if defined(_x86) || defined(_win32)
        pInterfaces[n].m_pvProxyEntry = (PVoid)&CInterfaceProxy::ProxyEntry;
#elif defined(_arm)
        pInterfaces[n].m_pvProxyEntry = (PVoid)&__ProxyEntry;
#elif defined(_mips)
        pInterfaces[n].m_pvProxyEntry = (PVoid)&ProxyContinue;
#else
#error unknown architecture
#endif

        // Hook all interfaces' IInterface to CObjectProxy except Aggregate.
        //
        pVtbl[0] = (UInt32)&CInterfaceProxy::S_Probe;
        pVtbl[1] = (UInt32)&CInterfaceProxy::S_AddRef;
        pVtbl[2] = (UInt32)&CInterfaceProxy::S_Release;

        // Fill v-table with proxy entry.
        // The proxy entrys's array begin from PROXY_ENTRY_BASE (0x7ffef000).
        //
        for (m = 3; m < cMethods; m++) {
            pVtbl[m] = PROXY_ENTRY_BASE + ((m - 3) << PROXY_ENTRY_SHIFT);
        }
    }

    // Invoke stub's AddRef()  and mark the oid_t in process struct
    //
    ec = CPseudoCentral::AttachImportService(oid);;

    if (FAILED(ec)) {
//        MARSHAL_DBGOUT(MSHDBG_ERROR, printf(
//            "SysInvoke failed, oid(%d), ec(%x)\n", oid, ec));
        goto ErrorExit;
    }

    ec = RegisterImportObject(oid, pProxy);
    if (FAILED(ec)) {
        MARSHAL_DBGOUT(MSHDBG_ERROR, printf(
            "Create proxy: register import object failed, oid(%d), ec(%x)\n",
            oid, ec));
        goto ErrorExit;
    }

    *ppIProxy = (IProxy *)pProxy;

    pProxy->AddRef();
    return NOERROR;

ErrorExit:
    delete pProxy;
    return ec;
}

CObjectProxy::~CObjectProxy()
{
    if (m_pInterfaces) {
        int n;

        for (n = 0; n < m_cInterfaces; n++) {
            if (m_pInterfaces[n].m_pvVptr) {
                delete [] (UInt32 *)(m_pInterfaces[n].m_pvVptr);
            }
        }
        delete [] m_pInterfaces;
    }
}

